﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using webapi_demo.CustomerExtension.Auth;

namespace webapi_demo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            ////创建了一个“AtLeast21”策略。 它只有一个要求—，即最低年龄，以参数的形式传递给要求。
            //services.AddAuthorization(options => {
            //    options.AddPolicy("admin", policy => policy.Requirements.Add(new MinimumAgeRequirement()));
            //});

            services.AddAuthorization(option =>
            {
                //自定义一些策略，原理都是基于申明key和value的值进行比较或者是否有无

                #region 键值对对比的一些验证策略

                //onlyRober：jwt的申明部分有name=rober就能通过，也就是payLoad["name"]="rober"
                option.AddPolicy("onlyRober", policy => policy.RequireClaim("name", "rober"));

                //onlyAdminOrSuperUser:只有Admin和SuperUser角色的用户才能通过，实质上就是payLoad["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"]="Admin"或者“SuperUser”；
                option.AddPolicy("onlyAdminOrSuperUser", policy => policy.RequireClaim(ClaimTypes.Role, "Admin", "SuperUser"));

                ////multiClaim：多申明同时满足，实质上也就是payLoad["aud"]=“roberAudience”
                ///(通过config["JwtOption:Audience"]获取)，或者，
                ///有name这个申明项，payLoad["name"]，不管它的值是多少，当然这里的或者，也可以改为并且，把||改为&&，请仔细看上面的验证diamante
                ////多申明共同,申明中包含aud：rober或者申明中值有等于Rober的都可以通过
                //option.AddPolicy("multiClaim", policy => policy.RequireAssertion(context =>
                //{
                //    return context.User.HasClaim("aud", config["JwtOption:Audience"]) || context.User.HasClaim(c => c.Value == config["JwtOption:Name"]);
                //}));
                #endregion

                #region 自定义验证策略-https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/policies?view=aspnetcore-2.2

                //还有个自定义策略AgeRequireMent，这个和上一篇讲的类似，也是两个重要的类组成（AgeRequireHandler 和 AgeRequireMent ）
                //option.AddPolicy("ageRequire", policy => policy.Requirements.Add(new AgeRequireMent(20)));
                //option.AddPolicy("common", policy => policy.Requirements.Add(new CommonAuthorize()));
                #endregion


            }).AddAuthentication(option =>
            {
                option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(option =>
            {
                //if (!string.IsNullOrEmpty(config["JwtOption:SecurityKey"]))
                //{
                //    TokenContext.securityKey = config["JwtOption:SecurityKey"];
                //}
                //设置需要验证的项目
                option.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,//是否验证Issuer
                    ValidateAudience = true,//是否验证Audience
                    ValidateLifetime = true,//是否验证失效时间
                    ValidateIssuerSigningKey = true,//是否验证SecurityKey
                    //ValidAudience = config["JwtOption:Audience"],//Audience
                    //ValidIssuer = config["JwtOption:Issuer"],//Issuer，这两项和前面签发jwt的设置一致
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TokenContext.securityKey))//拿到SecurityKey
                };
            });

            ////自定义策略IOC添加
            //services.AddSingleton<IAuthorizationHandler, AgeRequireHandler>();
            //services.AddSingleton<IAuthorizationHandler, CommonAuthorizeHandler>();

            //如何使用 请翻到最末
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            #region 管道验证

            ////没参数 就使用此方法 代码简洁
            //app.UseCustomerAuthorizenMiddleware();

            ////匿名访问的url也可以定义在appsetting.json文件
            //app.UseMiddleware<JwtCustomerAuthorizeMiddleware>(Configuration["JwtOption:SecurityKey"], 
            //    new List<string>() { "/api/values/getjwt", "/" });

            #endregion



            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}
